package top.ivansong.cxf.registry;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import top.ivansong.cxf.registry.util.LocalUntil;
import top.ivansong.cxf.registry.api.RPCService;
import top.ivansong.cxf.registry.api.ServiceBeanInfo;
import top.ivansong.cxf.registry.api.ServiceRegistry;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;


/**
 * 服务提供者发布器
 * 实现InitializingBean 获取本地IP，生成服务的URL
 * 实现BeanPostProcessor，在cxf服务bean注入spring容器时过滤出带有RPCService注解的bean{@link RPCService}，
 * 将这些bean通过serviceRegistry{@link ServiceRegistry} 注册到注册中心
 * 
 * serviceRegistry{@link ServiceRegistry}:注册中心
 * serverPort:服务的端口号，默认8080
 * servicePath:cxf服务默认的前缀
 * protocol:cxf服务采用的协议，默认http
 * @author ivansong
 *
 */
public class ServiceProvideRegister implements InitializingBean, BeanPostProcessor {

	@Resource
	private ServiceRegistry serviceRegistry;

	private String serverPort = "8080";
	
	private String servicePath = "/services";
	
	private String protocol = "http";
	
	private String url;

	private String servicePackge = "top.hellod";

	private Map<String, ServiceBeanInfo> serviceCache = new HashMap<>();

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		Class<?> beanClass = bean.getClass();
		RPCServiceClass serviceClass = filterFromClass(beanClass);
		if (serviceClass != null) {
			regist(serviceClass.annotion, serviceClass.serviceClass);
		}
		return bean;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		String ip = LocalUntil.getLocalIP();
		url =  protocol + "://" + ip + ":" + serverPort.trim() + servicePath;
	}

	public void setServerPort(String serverPort) {
		this.serverPort = serverPort;
	}

	public void setServicePath(String servicePath) {
		this.servicePath = servicePath;
	}

	public void setProtocol(String protocol) {
		this.protocol = protocol;
	}

	public void setServicePackge(String servicePackge) {
		this.servicePackge = servicePackge;
	}

	private RPCServiceClass filterFromClass(Class<?> clazz) {
		if (clazz == null || Proxy.isProxyClass(clazz) || !clazz.getName().contains(servicePackge)) {
			return null;
		}
		Class<?>[] inter = clazz.getInterfaces();
		for (Class<?> clazz1 : inter) {
			Annotation[] annotations = clazz1.getDeclaredAnnotations();
			for (Annotation annotation : annotations) {
				if (annotation instanceof RPCService) {
					RPCServiceClass res = new RPCServiceClass();
					res.serviceClass = clazz1;
					res.annotion = (RPCService) annotation;
					return res;
				}
			}
		}
		return null;
	}

	private void regist(RPCService annotion, Class<?> beanClass) {
		ServiceBeanInfo bean = new ServiceBeanInfo();
		bean.setClassName(beanClass.getName());
		bean.setUrlMapping(annotion.mapping());
		bean.setUrl(url);
		serviceCache.put(beanClass.getName(), bean);
		serviceRegistry.registService(bean);
	}
	
	private class RPCServiceClass {
		Class<?> serviceClass;
		RPCService annotion;
	}
}
